iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
Software Development

當rust 遇上 cqrs & es系列 第 19

D19 add Reader Query

  • 分享至 

  • xImage
  •  

先建立讀者 DTO

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct ReaderDto {
    pub reader_id: String,
    pub name: String,
    pub books_borrowed: u32,
    pub books_borrows: Vec<ReaderBorrows>,
    pub next_due_date: Option<DateTime<Utc>>,
}

impl ReaderDto {
    pub fn next_due_date(&self) -> Option<DateTime<Utc>> {
        self.books_borrows
            .iter()
            .map(|record| record.due_date)
            .min()
    }
}

借閱資料

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct ReaderBorrows {
    pub book_id: String,
    pub book_name: String,
    pub borrowed_date: DateTime<Utc>,
    pub due_date: DateTime<Utc>,
}

讀者Query

#[derive(Debug, Clone)]
pub struct ReaderQuery {
    pub db: Surreal<Db>,
}

impl ReaderQuery {
    pub async fn insert_reader(&self,  reader_dto: &ReaderDto) {
        let _res : Option<ReaderDto> = self.db
            .create(("readers", reader_dto.reader_id.clone()))
            .content(reader_dto)
            .await.unwrap();
    }

    pub async fn get_reader(&self, id: String) -> ReaderDto {
        let result: Vec<ReaderDto> = self.db
            .query("SELECT * FROM readers WHERE reader_id = $id")
            .bind(("id", id))
            .await.unwrap()
            .take(0).unwrap();
        result.first().unwrap().clone()
    }
}

實作CQRS的 Query

#[async_trait]
impl Query<Reader> for ReaderQuery {
    async fn dispatch(&self, aggregate_id: &str, events: &[EventEnvelope<Reader>]) {
        for event in events {
            match &event.payload {
                ReaderEvent::ReaderCreated { name, id } => {
                    self.insert_reader(&ReaderDto {
                        reader_id: aggregate_id.to_string(),
                        name: name.to_string(),
                        books_borrowed: 0,
                        books_borrows: vec![],
                        next_due_date: None,
                    }).await;
                }
                ReaderEvent::BookBorrowed(borrow) => {
                    let mut reader = self.get_reader(aggregate_id.to_string()).await;
                    reader.books_borrowed += 1;
                    let book: Vec<BookDto> = self.db
                        .query("SELECT * FROM books WHERE book_id = $id")
                        .bind(("id", borrow.book_id.to_string()))
                        .await.unwrap()
                        .take(0).unwrap();
                    let book = book.first().unwrap();
                    reader.books_borrows.push(ReaderBorrows {
                        book_id: borrow.book_id.to_string(),
                        book_name: book.title.to_string(),
                        borrowed_date: borrow.borrowed_date,
                        due_date: borrow.due_date,
                    });
                    reader.next_due_date = reader.next_due_date();
                    let _res: Option<ReaderDto> = self.db
                        .update(("readers", aggregate_id))
                        .content(&reader)
                        .await.unwrap();
                }
                ReaderEvent::BookReturned(borrow) => {
                    let mut reader = self.get_reader(aggregate_id.to_string()).await;
                    reader.books_borrowed -= 1;
                    reader.books_borrows.retain(|record| record.book_id != borrow.book_id.to_string());
                    reader.next_due_date = reader.next_due_date();
                    let _res: Option<ReaderDto> = self.db
                        .update(("readers", aggregate_id))
                        .content(&reader)
                        .await.unwrap();
                }
            }
        }
    }
}

上一篇
D18 Query of Book in Surreal
下一篇
D20 test Reader Query
系列文
當rust 遇上 cqrs & es30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言